﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace RainEngine.Effects
{
    /// <summary>
    /// 对Ocean.fx文件的封装，用于绘制海面。
    /// </summary>
    public class OceanEffect : Effect
    {
        // Effect参数        
        EffectParameter worldViewProjParam;
        EffectParameter worldParam;
        EffectParameter eyePositionParam;
        EffectParameter bumpTextureParam;
        EffectParameter bumpTextureUVTileParam;
        EffectParameter cubeTextureParam; 
        EffectParameter bumpStrengthParam;
        EffectParameter waveSpeedsParam;
        EffectParameter waveHeightsParam;
        EffectParameter waveLengthsParam;
        EffectParameter waveDir12Param;
        EffectParameter waveDir34Param;        
        EffectParameter timeParam;

        Matrix world = Matrix.Identity;
        Matrix view = Matrix.Identity;
        Matrix projection = Matrix.Identity;

        EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;

        /// <summary>
        /// 获取或设置世界矩阵。世界矩阵改变时会影响effect的WorldViewProj参数
        /// </summary>
        public Matrix World
        {
            get { return world; }
            set
            {
                world = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置视矩阵,视矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix View
        {
            get { return view; }
            set
            {
                view = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置投影矩阵,,投影矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix Projection
        {
            get { return projection; }
            set
            {
                projection = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置相机位置。
        /// </summary>
        public Vector3 EyePosition
        {
            get { return eyePositionParam .GetValueVector3 (); }
            set { eyePositionParam.SetValue(value); }
        }
        
        /// <summary>
        /// 获取或设置海面的凹凸贴图。
        /// </summary>
        public Texture2D BumpTexture
        {
            get { return bumpTextureParam.GetValueTexture2D(); }
            set { bumpTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置凹凸贴图的平铺次数，默认为Vector2.One。
        /// </summary>
        public Vector2 BumpTextureUVTile
        {
            get { return bumpTextureUVTileParam.GetValueVector2(); }
            set { bumpTextureUVTileParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置海面要反射的立方纹理
        /// </summary>
        public TextureCube CubeTexture
        {
            get { return cubeTextureParam.GetValueTextureCube(); }
            set { cubeTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置凹凸贴图强度，此值越大，海面的凹凸感越强，默认为0.5。
        /// </summary>
        public float BumpStrength
        {
            get { return bumpStrengthParam.GetValueSingle(); }
            set { bumpStrengthParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置波速，4个分量对应4个波的速度，默认值为Vector4(1, 2, 0.5f, 1.5f)。
        /// </summary>
        public Vector4 WaveSpeeds
        {
            get { return waveSpeedsParam.GetValueVector4 (); }
            set { waveSpeedsParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置振幅，4个分量对应4个波的振幅，默认值为Vector4(0.3f, 0.4f, 0.2f, 0.3f)。
        /// </summary>
        public Vector4 WaveHeights
        {
            get { return waveHeightsParam.GetValueVector4 (); }
            set { waveHeightsParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置波长，4个分量对应4个波的波长，默认值为Vector4(10, 5, 15, 7）。
        /// </summary>
        public Vector4 WaveLengths
        {
            get { return waveLengthsParam.GetValueVector4 (); }
            set { waveLengthsParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置第1、2个波的方向，前两个分量表示第1个波的方向，后两个分量表示第2个波的方向，默认值为Vector4(1.0f,0,1.0f,0.5f)。
        /// </summary>
        public Vector4 WaveDir12
        {
            get { return waveDir12Param.GetValueVector4 (); }
            set { waveDir12Param.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置第3、4个波的方向，前两个分量表示第3个波的方向，后两个分量表示第4个波的方向，默认值为Vector4(1, 0.7f, 1, -0.5f)。
        /// </summary>
        public Vector4 WaveDir34
        {
            get { return waveDir34Param.GetValueVector4 (); }
            set { waveDir34Param.SetValue(value);}
        }

        /// <summary>
        /// 设置时间变量
        /// </summary>
        public float Time
        {
            set { timeParam.SetValue(value); }
        }


        /// <summary>
        /// 创建一个新OceanEffect对象。
        /// </summary>
        public OceanEffect(GraphicsDevice device)
            : base(device, Resource.OceanEffectBin )
        {
            CacheEffectParameters(null);
        }

        /// <summary>
        /// 通过从一个已经存在的对象中复制参数创建一个新OceanEffect对象。
        /// </summary>
        protected OceanEffect(OceanEffect cloneSource)
            : base(cloneSource)
        {
            CacheEffectParameters(cloneSource);

            world = cloneSource.world;
            view = cloneSource.view;
            projection = cloneSource.projection;
        }


        /// <summary>
        /// 创建一个当前OceanEffect对象的副本。
        /// </summary>
        public override Effect Clone()
        {
            return new OceanEffect(this);
        }

        /// <summary>
        /// 缓存effect的参数。
        /// </summary>
        void CacheEffectParameters(OceanEffect cloneSource)
        {
            worldParam = Parameters["World"];
            worldViewProjParam = Parameters["WorldViewProj"];
            eyePositionParam = Parameters["EyePosition"];
            
            cubeTextureParam = Parameters["CubeTexture"];
            bumpTextureParam = Parameters["BumpTexture"];
            bumpTextureUVTileParam = Parameters["TextureUVTile"];
            bumpStrengthParam = Parameters["BumpStrength"];
            waveSpeedsParam = Parameters["WaveSpeeds"];
            waveHeightsParam = Parameters["WaveHeights"];
            waveLengthsParam = Parameters["WaveLengths"];
            waveDir12Param = Parameters["WaveDir12"];
            waveDir34Param = Parameters["WaveDir34"];
            timeParam = Parameters["Time"];
        }

        /// <summary>
        /// 在施加effect前根据需要重新计算effect参数。
        /// </summary>
        protected override void OnApply()
        {
            // 重新计算WorldViewProj组合矩阵
            if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
            {
                Matrix worldView = Matrix.Multiply(world, view);
                Matrix worldViewProj = Matrix.Multiply(worldView, projection);
                worldViewProjParam.SetValue(worldViewProj);
                worldParam.SetValue(world);

                dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
            }
        }
    }
}